import { existsSync } from 'node:fs';
import { join } from 'node:path';

import type { Options as ArgonOptions } from 'argon2';
import { argon2id, hash, verify } from 'argon2';

import { format, zonedTimeToUtc } from 'date-fns-tz';
// import { pick } from 'helper-fns';

import type { Observable } from 'rxjs';
import { from } from 'rxjs';

const argon2Options: ArgonOptions & { raw?: false } = {
  type: argon2id,
  hashLength: 50,
  saltLength: 32,
  timeCost: 4,
};

export const HelperService = {
  isDev() {
    process.env.NODE_ENV?.startsWith('dev');
  },
  /**
   * 判断当前的环境是否为生产环境
   * @returns { boolean }
   */
  isProd(): boolean {
    return process.env.NODE_ENV?.startsWith('prod');
  },
  getAppRootDir() {
    let currentDirectory = __dirname;

    while (!existsSync(join(currentDirectory, 'resources')))
      currentDirectory = join(currentDirectory, '..');

    return process.env.NODE_ENV === 'prod'
      ? join(currentDirectory, 'dist')
      : currentDirectory;
  },

  hashString(userPassword: string): Promise<string> {
    return hash(userPassword, argon2Options);
  },

  verifyHash(
    userPassword: string,
    passwordToCompare: string,
  ): Observable<boolean> {
    return from(verify(userPassword, passwordToCompare, argon2Options));
  },

  /* The `getTimeInUtc` function takes a `Date` object or a string representation of a date as input and
  returns a new `Date` object representing the same date and time in UTC timezone. */
  getTimeInUtc(date: Date | string): Date {
    const thatDate = date instanceof Date ? date : new Date(date);
    const currentUtcTime = zonedTimeToUtc(thatDate, 'UTC');

    return new Date(format(currentUtcTime, 'yyyy-MM-dd HH:mm:ss'));
  },
};
